package com.bii.gelapp;

import java.util.ArrayList;

import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

public class CompareTouchImageView extends ImageView {

	Matrix matrix;

	// We can be in one of these 3 states
	static final int NONE = 0;
	static final int DRAG = 1;
	static final int ZOOM = 2;
	static final int CLICK = 3;
	int mode = NONE;

	// only allow values
	boolean editmode = false;

	PointF last = new PointF();
	PointF start = new PointF();
	float minScale = 1f;
	float maxScale = 8f;
	float[] m;

	int viewWidth, viewHeight;
	float saveScale = 1f;
	protected float origWidth, origHeight;
	int oldMeasuredWidth, oldMeasuredHeight;

	public Bitmap originalBmp;

	ScaleGestureDetector mScaleDetector;

	GestureDetector gestureDetector;

	Context context;
	Bitmap bmap;
	Mat drawmat;
	// public static ArrayList<MarkerConnectedComponent> markersconnectedlist =
	// new ArrayList<MarkerConnectedComponent>();
	public static ArrayList<ConnectedComponent> markerlist = new ArrayList<ConnectedComponent>();
	public static ArrayList <Integer> markervalues = new ArrayList<Integer>();
	public ArrayList <Integer>markeroriginalvalues = new ArrayList<Integer>();
	
	// set maximum zoom for matrix
	public void setMaxZoom(float x) {
		maxScale = x;
	}

	// used especially for setting the mode to edit

	public CompareTouchImageView(Context context, Bitmap bmp) {
		super(context);
		originalBmp = bmp;
		// TODO Auto-generated constructor stub
		sharedConstructing(context);
	}

	private void sharedConstructing(final Context context) {
		// preparation for all the image loading and stuffs
		super.setClickable(true);
		this.context = context;

		/*
		 * if (circlelist.size() > 0) { drawCircles(); }
		 */

		bmap = originalBmp;
		drawmat = new Mat(bmap.getHeight(), bmap.getWidth(), CvType.CV_8U);
		// get all component list from fullactivity
		markerlist = CompareFullScreenActivity.markerlist;
		markervalues = CompareFullScreenActivity.markervalues;
		markeroriginalvalues = (ArrayList<Integer>) CompareFullScreenActivity.markervalues.clone();


		if (markerlist.size() > 0) {
			// drawMarkers();
			drawRectangles();
		}

		mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
		matrix = new Matrix();
		m = new float[9];
		setImageMatrix(matrix);
		// allow scaling of image by matrix
		setScaleType(ScaleType.MATRIX);

		// used for drawing circles

		setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				mScaleDetector.onTouchEvent(event);
				PointF curr = new PointF(event.getX(), event.getY());
				long starttime = 0;
				long endtime = 0;

				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					last.set(curr);
					start.set(last);
					mode = DRAG;

					Matrix inverse = new Matrix();
					getImageMatrix().invert(inverse);
					float[] touchPoint = new float[] { event.getX(),
							event.getY() };
					inverse.mapPoints(touchPoint);
					for (int i = 0; i < markerlist.size(); i++) {
						float itop = markerlist.get(i).top;
						float ileft = markerlist.get(i).left;
						float iright = markerlist.get(i).right;
						float ibottom = markerlist.get(i).bottom;

						if (itop > ibottom) {
							float temp;
							temp = itop;
							itop = ibottom;
							ibottom = temp;
						}
						if (ileft > iright) {
							float temp;
							temp = ileft;
							ileft = iright;
							iright = temp;
						}

						if (touchPoint[0] <= iright && touchPoint[0] >= ileft) {
							if (touchPoint[1] <= ibottom
									&& touchPoint[1] >= itop) {

								CompareEditDialog comparedialog = new CompareEditDialog(
										context, i);
								comparedialog.show();
							}
						}
					}
					drawRectangles();
					break;

				case MotionEvent.ACTION_MOVE:

					if (mode == DRAG) {

						// get the new horizontal and vertical positions
						float deltaX = curr.x - last.x;
						float deltaY = curr.y - last.y;
						// if view width is larger than content size
						// (original
						// width and height) returns 0
						float fixTransX = getFixDragTrans(deltaX, viewWidth,
								origWidth * saveScale);
						float fixTransY = getFixDragTrans(deltaY, viewHeight,
								origHeight * saveScale);
						matrix.postTranslate(fixTransX, fixTransY);
						fixTrans();
						last.set(curr.x, curr.y);

					}

					break;

				case MotionEvent.ACTION_UP:

					mode = NONE;

					int xDiff = (int) Math.abs(curr.x - start.x);
					int yDiff = (int) Math.abs(curr.y - start.y);
					if (xDiff < CLICK && yDiff < CLICK)
						performClick();

					break;

				case MotionEvent.ACTION_POINTER_UP:

					mode = NONE;

					break;
				}

				setImageMatrix(matrix);

				invalidate();
				return true; // indicate event was handled
			}

		});
	}

	private void drawRectangles() {
		Utils.bitmapToMat(bmap, drawmat);
		for (int i = 0; i < markerlist.size(); i++) {
			if(markervalues.get(i) == markeroriginalvalues.get(i)){
				Core.rectangle(drawmat, new Point(markerlist.get(i).left,
						markerlist.get(i).top), new Point(markerlist.get(i).right,
						markerlist.get(i).bottom), new Scalar(255, 0, 0), 2);
			}
			else
			{
				Core.rectangle(drawmat, new Point(markerlist.get(i).left,
						markerlist.get(i).top), new Point(markerlist.get(i).right,
						markerlist.get(i).bottom), new Scalar(0, 255, 0), 2);
			}
		}
		Bitmap drawnbmp = Bitmap.createBitmap(drawmat.cols(), drawmat.rows(),
				Bitmap.Config.RGB_565);
		Utils.matToBitmap(drawmat, drawnbmp);
		setImageBitmap(drawnbmp);

	};

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {

		@Override
		public boolean onScaleBegin(ScaleGestureDetector detector) {
			mode = ZOOM;
			return true;
		}

		@Override
		public boolean onScale(ScaleGestureDetector detector) {

			float mScaleFactor = detector.getScaleFactor();
			float origScale = saveScale;
			saveScale *= mScaleFactor;

			if (saveScale > maxScale) {
				// prevent zooming in too much
				saveScale = maxScale;
				mScaleFactor = maxScale / origScale;
			} else if (saveScale < minScale) {
				// prevent zooming out too much
				saveScale = minScale;
				mScaleFactor = minScale / origScale;
			}

			if (origWidth * saveScale <= viewWidth
					|| origHeight * saveScale <= viewHeight)
				matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
						viewHeight / 2);
			else
				matrix.postScale(mScaleFactor, mScaleFactor,
						detector.getFocusX(), detector.getFocusY());

			fixTrans();
			/*
			 * Log.d("tag1", "Bitmap size: " + ((BitmapDrawable)
			 * getDrawable()).getBitmap().getWidth() + " " + ((BitmapDrawable)
			 * getDrawable()).getBitmap().getHeight()); Log.d("tag1",
			 * "Image view size: " + getWidth() + " " + getHeight());
			 */
			return true;
		}

	}

	void fixTrans() {
		matrix.getValues(m);
		float transX = m[Matrix.MTRANS_X];
		float transY = m[Matrix.MTRANS_Y];

		float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
		float fixTransY = getFixTrans(transY, viewHeight, origHeight
				* saveScale);
		// if view height and width is not larger than original height and
		// weight, matrix would be created
		if (fixTransX != 0 || fixTransY != 0)
			matrix.postTranslate(fixTransX, fixTransY);
	}

	float getFixTrans(float trans, float viewSize, float contentSize) {
		float minTrans, maxTrans;

		if (contentSize <= viewSize) {
			minTrans = 0;
			maxTrans = viewSize - contentSize;
		} else {
			minTrans = viewSize - contentSize;
			maxTrans = 0;
		}

		if (trans < minTrans)
			return -trans + minTrans;
		if (trans > maxTrans)
			return -trans + maxTrans;
		return 0;
	}

	float getFixDragTrans(float delta, float viewSize, float contentSize) {
		if (contentSize <= viewSize) {
			return 0;
		}
		return delta;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		viewWidth = MeasureSpec.getSize(widthMeasureSpec);
		viewHeight = MeasureSpec.getSize(heightMeasureSpec);

		//
		// Rescales image on rotation
		//
		if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
				|| viewWidth == 0 || viewHeight == 0)
			return;
		oldMeasuredHeight = viewHeight;
		oldMeasuredWidth = viewWidth;

		if (saveScale == 1) {
			// Fit to screen.
			float scale;

			Drawable drawable = getDrawable();
			if (drawable == null || drawable.getIntrinsicWidth() == 0
					|| drawable.getIntrinsicHeight() == 0)
				return;
			int bmWidth = drawable.getIntrinsicWidth();
			int bmHeight = drawable.getIntrinsicHeight();

			// Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " +
			// bmHeight);

			float scaleX = (float) viewWidth / (float) bmWidth;
			float scaleY = (float) viewHeight / (float) bmHeight;
			scale = Math.min(scaleX, scaleY);
			matrix.setScale(scale, scale);

			// Center the image
			float redundantYSpace = (float) viewHeight
					- (scale * (float) bmHeight);
			float redundantXSpace = (float) viewWidth
					- (scale * (float) bmWidth);
			redundantYSpace /= (float) 2;
			redundantXSpace /= (float) 2;

			matrix.postTranslate(redundantXSpace, redundantYSpace);

			origWidth = viewWidth - 2 * redundantXSpace;
			origHeight = viewHeight - 2 * redundantYSpace;
			setImageMatrix(matrix);
		}
		fixTrans();
	}

}
